﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using VisionCloud.Domain.Common;
using VisionCloud.Utility;

namespace VisionCloud.Domain.Extension
{
    public static class IQueryableExtensions
    {
        /// <summary>
        /// 分页+排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="condition">排序条件(注：支持一个字段)</param>
        /// <returns></returns>
        public static IOrderedQueryable<T> PageOrderBy<T>(this IQueryable<T> source, PageBase condition)
        {
            if (condition == null)
            {
                return null;
            }

            if (string.Equals(condition.AscDesc, "ASC", StringComparison.OrdinalIgnoreCase))
            {
                return InternalOrder<T>(source, condition.OrderBy, "OrderBy");
            }
            else if (string.Equals(condition.AscDesc, "DESC", StringComparison.OrdinalIgnoreCase))
            {
                return InternalOrder<T>(source, condition.OrderBy, "OrderByDescending");
            }
            return null;
        }

        public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, String propertyName)
        {
            return InternalOrder<T>(source, propertyName, "OrderBy");
        }

        public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, String propertyName)
        {
            return InternalOrder<T>(source, propertyName, "OrderByDescending");
        }

        public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, String propertyName)
        {
            return InternalOrder<T>(source, propertyName, "ThenBy");
        }

        public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, String propertyName)
        {
            return InternalOrder<T>(source, propertyName, "ThenByDescending");
        }

        private static IOrderedQueryable<T> InternalOrder<T>(IQueryable<T> source, String propertyName, String methodName)
        {
            Type type = typeof(T);
            ParameterExpression arg = Expression.Parameter(type, "p");
            PropertyInfo property = type.GetProperty(propertyName);
            // 排序字段是否存在
            if (property == null)
            {
                throw new OperationException(string.Format(StartupServer.CommonLocalizer["YB0450"].Value, propertyName));
            }
            Expression expr = Expression.Property(arg, property);
            Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), property.PropertyType);
            LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

            return ((IOrderedQueryable<T>)(typeof(Queryable).GetMethods().Single(
                p => String.Equals(p.Name, methodName, StringComparison.Ordinal)
                    && p.IsGenericMethodDefinition
                    && p.GetGenericArguments().Length == 2
                    && p.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(T), property.PropertyType)
                .Invoke(null, new Object[] { source, lambda })));
        }
    }
}